package com.demo.webapp.kcfinder.context;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;

import com.demo.webapp.kcfinder.ActionMapping;
import com.demo.webapp.kcfinder.action.Action;
import com.demo.webapp.kcfinder.utils.ValueStack;

/**
 * ActionContext
 * 提供请求线程的局部变量,为Action提供请求需要的上下文参数
 * 如果扩展该ActionContext则为Action将提供更多的上下文参数
 * 
 * ActionContext在线程结束后被销毁
 * 
 * @author ryuu.kk
 *
 */
public class ActionContext implements Serializable {

	/**
	 * ID
	 */
	private static final long serialVersionUID = -7532036093373076592L;

	/**
	 * ThreadLocal：ActionContext
	 */
	private static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
	
	public static final String VALUE_STACK = ValueStack.VALUE_STACK;
	public static final String SESSION = "_kcfinder.session";
	public static final String COOKIES = "_kcfinder.cookies";
	public static final String REQUEST = "_kcfinder.request";
	public static final String RESPONSE = "_kcfinder.response";
	public static final String APPLICATION = "_kcfinder.application";
	public static final String PARAMETERS = "_kcfinder.parameters";
	public static final String LOCALE = "_kcfinder.locale";
	public static final String THEMES = "_kcfinder.themes";
	public static final String ACTION = "_kcfinder.action";
	public static final String ACTION_MAPPING = "_kcfinder.action.mapping";
	public static final String SERVLET_CONTEXT = "_kcfinder.servletContext";
	public static final String ACTION_ENCODING = "_kcfinder.encoding";
	
	/**文件的公共存放路径**/
	public static final String SERVLET_PUBLIC_PATH = "_kcfinder.public.path";
	/**Servlet允许的访问路径**/
	public static final String SERVLET_ALLOW_PATH = "_kcfinder.allow.path";
	
	/**Action的执行结果**/
	public static final String ACTION_RESULT = "_kcfinder.action.result";
	
	/**
	 * 参数Map
	 */
	private Map<String, Object> context;
	
	/**
	 * 构造函数
	 */
	public ActionContext() {
		context = new HashMap<String, Object>();
	}
	
	/**
	 * 构造函数
	 */
	public ActionContext(Map<String, Object> map) {
		context = map;
	}
	
	//~~ VALUE STACK HERE
    public ValueStack getValueStack() {
        return (ValueStack) get(VALUE_STACK);
    }
    public void setValueStack(ValueStack stack) {
        put(VALUE_STACK, stack);
    }

	//~~ SERVLET CONTEXT HERE
	public void setServletContext(ServletContext context) {
		put(SERVLET_CONTEXT, context);
	}
	
	public ServletContext getServletContext() {
		return get(SERVLET_CONTEXT);
	}
	
	//~~ SESSION HERE
	public void setSession(Map<String, Object> session) {
		put(SESSION, session);
	}
	
	public Map<String, Object> getSession() {
		return get(SESSION);
	}
	
	//~~ REQUEST HERE
	public void setRequest(HttpServletRequest request) {
		put(REQUEST, request);
	}
	
	public HttpServletRequest getRequest() {
		return get(REQUEST);
	}
	
	//~~ RESPONSE HERE
	public void setResponse(HttpServletResponse response) {
		put(RESPONSE, response);
	}
	
	public HttpServletResponse getResponse() {
		return get(RESPONSE);
	}
	
	//~~ PARAMETERS HERE
	public void setParameters(Map<String, Object> parameters) {
		put(PARAMETERS, parameters);
	}
	
	public Map<String, Object> getParameters() {
		return get(PARAMETERS);
	}
	
	//~~ APPLICATION HERE
	public void setApplication(Map<String, Object> application) {
		put(APPLICATION, application);
	}
	
	public Map<String, Object> getApplication() {
		return get(APPLICATION);
	}
	
	//~~ LOCALE HERE
	public void setLocale(Locale locale) {
		put(LOCALE, locale);
	}
	
	public Locale getLocale() {
		Locale locale = (Locale) get(LOCALE);

		if (locale == null) {
			locale = Locale.getDefault();
		    setLocale(locale);
		}
		return locale;
	}
	
	//~~ COOKIES HERE
	public void setCookies(Cookie[] cookies) {
		put(COOKIES, cookies);
	}
	public Cookie[] getCookies() {
		return get(COOKIES);
	}
	
	//~~ THEMES HERE
	public void setThemes(String themes) {
		put(THEMES, themes);
	}
	public String getThemes() {
		return get(THEMES);
	}
	
	//~~ ACTION MAPPING HERE
	public void setActionMapping(ActionMapping mapping) {
		put(ACTION_MAPPING, mapping);
	}
	public ActionMapping getActionMapping() {
		return get(ACTION_MAPPING);
	}
	
	//~~ ACTION HERE
	public void setAction(Action action) {
		put(ACTION, action);
	}
	
	public Action getAction() {
		return get(ACTION);
	}
	
	//~~ ACTION RESULT HERE
	public void setResult(Map<String, Object> result) {
		put(ACTION_RESULT, result);
	}
	
	public Map<String, Object> getResult() {
		return get(ACTION_RESULT);
	}
	
	//~~ ACTION ENCODING HERE
	public void setEncoding(String encoding) {
		put(ACTION_ENCODING, encoding);
	}
	
	public String getEncoding() {
		return get(ACTION_ENCODING);
	}
	
	//~~ ACTION PUBLIC PATH HERE
	public void setPublishPath(String path) {
		put(SERVLET_PUBLIC_PATH, path);
	}
	
	public String getPublicPath() {
		return get(SERVLET_PUBLIC_PATH);
	}
	
	//~~ ACTION ALLOW ACCESS PATH HERE
	public void setAllowPath(String... paths) {
		if (paths == null || paths.length == 0) {
			paths = new String[]{getPublicPath()};
		}
		Set<String> pathSet = new HashSet<String>(); 
		for (String path : paths) {
			if (!path.startsWith("/")) {
				path = "/" + path;
			}
			pathSet.add(path);
		}
		put(SERVLET_ALLOW_PATH, pathSet);
	}
	// 是否允许访问该地址,该地址只是一个允许kcfinder访问的地址,并非用户授权地址
	public boolean isAllowPath(String path) {
		Object res = get(SERVLET_ALLOW_PATH);
		if (res != null && res instanceof Set) {
			Set<String> pathSet = (Set<String>) res;
			if (!path.startsWith("/")) {
				path = "/" + path;
			}
			return pathSet.contains(path);
		}
		return false;
	}
	
	
	//~~ ACTION CONTEXT CLOCK
	public void lock(String key, Boolean clock) {
		put(key, clock);
	}
	
	public <E> E getLock(String key) {
		return get(key);
	}
	
	public String getValue(String key, String defValue) {
		String value = this.getRequest().getParameter(key);
		if (value == null) {
			value = (String) this.getRequest().getAttribute(key);
		}
		if (value == null) {
			value = (String) this.getSession().get(key);
		}
		if (StringUtils.isEmpty(value)) {
			return defValue;
		}
		return value;
	}
	
	public String[] getValues(String key, String... defValue) {
		String[] value = this.getRequest().getParameterValues(key);
		if (value == null) {
			value = (String[]) this.getRequest().getAttribute(key);
		}
		if (value == null) {
			value = (String[]) this.getSession().get(key);
		}
		if (value == null) {
			return defValue;
		}
		return value;
	}
	
	public Boolean getValue(String key, Boolean... defVal) {
		String value = getValue(key, "");
		//ValueStack vs = getValueStack();
		//vs.findValue(key, false);
		return StringUtils.isEmpty(value) ? ((defVal != null && defVal.length > 0) ? defVal[0] : Boolean.FALSE) : Boolean.FALSE;
	}
	
	public Long getValue(String key, Long... defVal) {
		String value = getValue(key, "");
		//ValueStack vs = getValueStack();
		//vs.findValue(key, false);
		return NumberUtils.toLong(value, (defVal != null && defVal.length > 0) ? defVal[0] : 0);
	}
	
	public int getValue(String key, int... defVal) {
		String value = getValue(key, "");
		return NumberUtils.toInt(value, (defVal != null && defVal.length > 0) ? defVal[0] : 0);
	}
	
	public double getValue(String key, double... defVal) {
		String value = getValue(key, "");
		return NumberUtils.toDouble(value, (defVal != null && defVal.length > 0) ? defVal[0] : 0);
	}
	
	public float getValue(String key, float... defVal) {
		String value = getValue(key, "");
		return NumberUtils.toFloat(value, (defVal != null && defVal.length > 0) ? defVal[0] : 0);
	}
	
	protected void put(String key, Object value) {
		context.put(key, value);
	}
	
	@SuppressWarnings("unchecked")
	protected <E> E get(String key) {
		return (E) context.get(key);
	}
    
    /**
     * 取得容器上下文
     * 当Context为NULL由调用类处理
     * @return ActionContext
     */
    public static ActionContext getContext() {
        return (ActionContext) actionContext.get();
    }
	
    public static void setContext(ActionContext context) {
        actionContext.set(context);
    }
}
